home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / support / shmemdoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-11  |  25.2 KB  |  1,093 lines

  1. /*
  2.  *  shmemdoc.c -- Shared memory doctor for POSTGRES.
  3.  *
  4.  *    This program lets you view the state of shared memory and
  5.  *    semaphores after an abnormal termination.  It assumes that
  6.  *    state is static -- that is, no other process should be changing
  7.  *    shared memory while this one is running.  In order to use this,
  8.  *    you should start the postmaster with the -n option (noreinit)
  9.  *    in order to avoid reinitializing shared structures after a backend
  10.  *    terminates abnormally.
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include <sys/ipc.h>
  16. #include <sys/shm.h>
  17. #include <sys/sem.h>
  18.  
  19. #include "tmp/c.h"
  20. #include "support/shmemipc.h"
  21. #include "support/shmemipci.h"
  22. #include "utils/memutils.h"
  23.  
  24. RcsId("$Header: /private/postgres/src/support/RCS/shmemdoc.c,v 1.3 1992/08/18 17:58:37 mao Exp $");
  25.  
  26. /* default port for ipc connections (used to generate ipc key) */
  27. #define    DEF_PORT    4321
  28. #define    DEF_NBUFS    64
  29. #define LBUFSIZ        512
  30. #define MAXARGS        10
  31.  
  32. extern int    optind, opterr;
  33. extern char    *optarg;
  34. extern int    errno;
  35.  
  36. typedef struct _Cmd {
  37.     char    *cmd_name;
  38.     int        cmd_nargs;
  39.     int        (*cmd_func)();
  40. } Cmd;
  41.  
  42. extern int    getsize();
  43. extern void    cmdloop();
  44. extern void    shmemsplit();
  45. extern int    semstat();
  46. extern int    semset();
  47. extern int    quit();
  48. extern int    help();
  49. extern int    setbase();
  50. extern int    whatis();
  51. extern int    shmemstat();
  52. extern int    bufdesc();
  53. extern int    bufdescs();
  54. extern int    buffer();
  55. extern int    linp();
  56. extern int    tuple();
  57.  
  58. Cmd    CmdList[] = {
  59.     "bufdesc",        1,    bufdesc,
  60.     "bufdescs",        0,    bufdescs,
  61.     "buffer",        3,    buffer,
  62.     "help",        0,    help,
  63.     "linp",        2,    linp,
  64.     "quit",        0,    quit,
  65.     "semset",        2,    semset,
  66.     "semstat",        0,    semstat,
  67.     "setbase",        1,    setbase,
  68.     "shmemstat",    0,    shmemstat,
  69.     "tuple",        3,    tuple,
  70.     "whatis",        1,    whatis,
  71.     (char *) NULL,    0,    NULL
  72. };
  73.  
  74. char *SemNames[] = {
  75.     "shared memory lock",
  76.     "binding lock",
  77.     "buffer manager lock",
  78.     "lock manager lock",
  79.     "shared inval cache lock",
  80. #ifdef SONY_JUKEBOX
  81.     "sony jukebox cache lock",
  82.     "jukebox spinlock",
  83. #endif
  84. #ifdef MAIN_MEMORY
  85.     "main memory cache lock",
  86. #endif
  87.     "proc struct lock",
  88.     "oid generation lock",
  89.     (char *) NULL
  90. };
  91.  
  92. typedef struct LRelId {
  93.     unsigned long    relId;
  94.     unsigned long    dbId;
  95. } LRelId;
  96.  
  97. typedef struct BufferTag {
  98.     LRelId        relId;
  99.     unsigned long    blockNum;
  100. } BufferTag;
  101.  
  102. typedef struct BufferDesc {
  103.     int            freeNext;
  104.     int            freePrev;
  105.     unsigned int    data;
  106.     BufferTag        tag;
  107.     int            id;
  108.     unsigned short    flags;
  109.     short        bufsmgr;
  110.     unsigned        refcount;
  111.     char        sb_dbname[16];
  112.     char        sb_relname[16];
  113. #ifdef HAS_TEST_AND_SET
  114.     slock_t        io_in_progress_lock;
  115. #endif /* HAS_TEST_AND_SET */
  116. } BufferDesc;
  117.  
  118. char        *Base;
  119. char        *SharedRegion;
  120. int        SemaphoreId;
  121. int        NBuffers;
  122. char        *BindingTable;
  123. BufferDesc    *BufferDescriptors;
  124. char        *BufferBlocks;
  125. #ifndef HAS_TEST_AND_SET
  126. int        *NWaitIOBackend;
  127. #endif /* ndef HAS_TEST_AND_SET */
  128. char        *BufHashTable;
  129. char        *LockTableCtl;
  130. char        *LockTableLockHash;
  131. char        *LockTableXIDHash;
  132. char        *SharedRegionEnd;
  133. char        *LastKnownSMAddr;
  134.  
  135. typedef struct ItemIdData {
  136.     unsigned        lp_off:13,        /* offset to tuple */
  137.             lp_flags:6,        /* itemid flags */
  138.             lp_len:13;        /* length of tuple */
  139. } ItemIdData;
  140.  
  141. #define LP_USED        0x01    /* this line pointer is being used */
  142. #define LP_IVALID    0x02    /* this tuple is known to be insert valid */
  143. #define LP_DOCNT    0x04    /* this tuple continues on another page */
  144. #define LP_CTUP        0x08    /* this is a continuation tuple */
  145. #define LP_LOCK        0x10    /* this is a lock */
  146. #define LP_ISINDEX    0x20    /* this is an internal index tuple */
  147.  
  148. typedef struct ItemPointerData {
  149.     unsigned short    block[2];
  150.     unsigned short    offset;
  151. } ItemPointerData;
  152.  
  153. typedef struct HeapTupleData {
  154.     unsigned int    t_len;
  155.     ItemPointerData    t_ctid;
  156.     ItemPointerData    t_chain;
  157.     union {
  158.     ItemPointerData        l_ltid;
  159.     char            *l_lock;    /* actually a RuleLock */
  160.     } t_lock;
  161.     unsigned long    t_oid;
  162.     unsigned short    t_cmin;
  163.     unsigned short    t_cmax;
  164.     unsigned long    t_xmin;
  165.     unsigned long    t_xmax;
  166.     unsigned long    t_tmin;
  167.     unsigned long    t_tmax;
  168.     unsigned short    t_natts;
  169.     char        t_vtype;
  170.     char        t_infomask;
  171.     char        t_locktype;
  172.     char        t_bits[1];
  173. } HeapTupleData;
  174.  
  175. typedef struct IndexTupleData {
  176.     ItemPointerData        t_tid;
  177.  
  178. #define ITUP_HASNULLS    0x8000
  179. #define ITUP_HASVARLENA    0x4000
  180. #define ITUP_HASRULES    0x2000
  181. #define ITUP_LENMASK    0x1fff
  182.  
  183.     unsigned short        t_info;
  184. } IndexTupleData;
  185.  
  186. typedef struct BTItemData {
  187.     unsigned long    bti_oid;
  188.     IndexTupleData    bti_itup;
  189. } BTItemData;
  190.  
  191. typedef struct PageHeaderData {
  192.     unsigned short    pd_lower;
  193.     unsigned short    pd_upper;
  194.     unsigned short    pd_special;
  195.     unsigned short    pd_opaque;
  196.     ItemIdData        pd_linp[1];        /* line pointers start here */
  197. } PageHeaderData;
  198.  
  199. typedef struct BTPageOpaqueData {
  200.     unsigned short    btpo_prev;
  201.     unsigned short    btpo_next;
  202.     unsigned short    btpo_flags;
  203. } BTPageOpaqueData;
  204.  
  205. typedef struct BTMetaPageData {
  206.     unsigned long    btm_magic;
  207.     unsigned long    btm_version;
  208.     unsigned long    btm_root;
  209.     unsigned long    btm_freelist;
  210. } BTMetaPageData;
  211.  
  212. typedef struct RTreePageOpaqueData {
  213.     unsigned long    rtpo_flags;
  214.  
  215. #define RTF_LEAF    (1 << 0)
  216.  
  217. } RTreePageOpaqueData;
  218.  
  219. #define BTP_LEAF    (1 << 0)
  220. #define BTP_ROOT    (1 << 1)
  221. #define BTP_FREE    (1 << 2)
  222.  
  223. main(argc, argv)
  224.     int argc;
  225.     char **argv;
  226. {
  227.     int c;
  228.     int errs;
  229.     int key, spinkey, memkey, shmid;
  230.     char *region;
  231.     int portno;
  232.     int size;
  233.  
  234.     errs = 0;
  235.     portno = DEF_PORT;
  236.     NBuffers = DEF_NBUFS;
  237.     while ((c = getopt(argc, argv, "B:p:")) != EOF) {
  238.     switch (c) {
  239.         case 'B':
  240.         NBuffers = atoi(optarg);
  241.         break;
  242.         case 'p':
  243.         portno = atoi(optarg);
  244.         break;
  245.         default:
  246.         fprintf(stderr, "unknown argument %c\n", c);
  247.         errs++;
  248.         break;
  249.     }
  250.     }
  251.  
  252.     if (errs) {
  253.     fprintf(stderr, "usage: %s [-p port]\n", *argv);
  254.     fflush(stderr);
  255.     exit (1);
  256.     }
  257.  
  258.     /* this has got to be a hirohamaism */
  259.     key = SystemPortAddressGetIPCKey(portno);
  260.     spinkey = IPCKeyGetSpinLockSemaphoreKey(key);
  261.  
  262.     SemaphoreId = semget(spinkey, 0, 0);
  263.     if (SemaphoreId < 0) {
  264.     fprintf(stderr, "%s: cannot attach semaphores (port %d)\n",
  265.         *argv, portno);
  266.     perror("semget");
  267.     fflush(stderr);
  268.     exit (1);
  269.     }
  270.  
  271.     size = getsize();
  272.     memkey = IPCKeyGetBufferMemoryKey(key);
  273.     shmid = shmget(memkey, size, 0);
  274.  
  275.     if (shmid < 0) {
  276.     fprintf(stderr, "%s: cannot identify shared memory by name\n", *argv);
  277.     perror("shmget");
  278.     fflush(stderr);
  279.     exit (1);
  280.     }
  281.  
  282.     Base = SharedRegion = region = (char *) shmat(shmid, 0, 0);
  283.     if (region == (char *) -1) {
  284.     fprintf(stderr, "%s: cannot attach shared memory\n", *argv);
  285.     perror("shmat");
  286.     fflush(stderr);
  287.     exit (1);
  288.     }
  289.     SharedRegionEnd = region + size;
  290.  
  291.     shmemsplit(region);
  292.  
  293.     cmdloop();
  294.  
  295.     exit (0);
  296. }
  297.  
  298. int
  299. getsize()
  300. {
  301.     /* XXX compute this, someday */
  302.     return(833820);
  303. }
  304.  
  305. void
  306. cmdloop()
  307. {
  308.     char *l;
  309.     char lbuf[LBUFSIZ];
  310.     char *cmd, *arg[MAXARGS];
  311.     int nargs;
  312.     int cmdno;
  313.     int status;
  314.  
  315.     printf("> ");
  316.     fflush(stdout);
  317.  
  318.     while ((l = fgets(lbuf, LBUFSIZ, stdin)) != (char *) NULL) {
  319.     lbuf[strlen(l) - 1] = '\0';
  320.     while (*l != '\0' && isspace(*l))
  321.         l++;
  322.     cmd = l;
  323.  
  324.     if (*cmd == '\0')
  325.         goto nextcmd;
  326.  
  327.     /* skip command and white space following it */
  328.     while (*l != '\0' && !isspace(*l))
  329.         l++;
  330.     if (*l != '\0') {
  331.         *l++ = '\0';
  332.         while (*l != '\0' && isspace(*l))
  333.         l++;
  334.     }
  335.  
  336.     /* consume one argument */
  337.     for (nargs = 0; nargs < MAXARGS && *l != '\0'; nargs++) {
  338.         arg[nargs] = l;
  339.         while (*l != '\0' && !isspace(*l))
  340.         l++;
  341.         if (*l != '\0') {
  342.         do
  343.             *l++ = '\0';
  344.         while (*l != '\0' && isspace(*l));
  345.         }
  346.     }
  347.  
  348.     for (cmdno = 0; CmdList[cmdno].cmd_name != (char *) NULL; cmdno++)
  349.         if (strcmp(CmdList[cmdno].cmd_name, cmd) == 0)
  350.         break;
  351.  
  352.     if (CmdList[cmdno].cmd_name == (char *) NULL) {
  353.         printf("%s unknown, 'help' for help\n", cmd);
  354.     } else if (CmdList[cmdno].cmd_nargs != nargs) {
  355.         printf("arg count mismatch: expected %d\n",
  356.            CmdList[cmdno].cmd_nargs);
  357.     } else {
  358.         switch (nargs) {
  359.         case 0:
  360.             status = (*(CmdList[cmdno].cmd_func))();
  361.             break;
  362.         case 1:
  363.             status = (*(CmdList[cmdno].cmd_func))(arg[0]);
  364.             break;
  365.         case 2:
  366.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  367.                               arg[1]);
  368.             break;
  369.         case 3:
  370.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  371.                               arg[1],
  372.                               arg[2]);
  373.             break;
  374.         case 4:
  375.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  376.                               arg[1],
  377.                               arg[2],
  378.                               arg[3]);
  379.             break;
  380.         case 5:
  381.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  382.                               arg[1],
  383.                               arg[2],
  384.                               arg[3],
  385.                               arg[4]);
  386.             break;
  387.         case 6:
  388.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  389.                               arg[1],
  390.                               arg[2],
  391.                               arg[3],
  392.                               arg[4],
  393.                               arg[5]);
  394.             break;
  395.         case 7:
  396.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  397.                               arg[1],
  398.                               arg[2],
  399.                               arg[3],
  400.                               arg[4],
  401.                               arg[5],
  402.                               arg[6]);
  403.             break;
  404.         case 8:
  405.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  406.                               arg[1],
  407.                               arg[2],
  408.                               arg[3],
  409.                               arg[4],
  410.                               arg[5],
  411.                               arg[6],
  412.                               arg[7]);
  413.             break;
  414.         case 9:
  415.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  416.                               arg[1],
  417.                               arg[2],
  418.                               arg[3],
  419.                               arg[4],
  420.                               arg[5],
  421.                               arg[6],
  422.                               arg[7],
  423.                               arg[8]);
  424.             break;
  425.         case 10:
  426.             status = (*(CmdList[cmdno].cmd_func))(arg[0],
  427.                               arg[1],
  428.                               arg[2],
  429.                               arg[3],
  430.                               arg[4],
  431.                               arg[5],
  432.                               arg[6],
  433.                               arg[7],
  434.                               arg[8],
  435.                               arg[9]);
  436.             break;
  437.         default:
  438.             fprintf(stderr, "illegal arg count %d\n", nargs);
  439.             fflush(stderr);
  440.             exit (1);
  441.         }
  442.  
  443.         if (status < 0) {
  444.         return;
  445.         } else if (status > 0) {
  446.         fprintf(stderr, "%s returns %d\n", CmdList[cmdno].cmd_name,
  447.             status);
  448.         fflush(stderr);
  449.         }
  450.     }
  451.  
  452. nextcmd:
  453.     printf("> ");
  454.     fflush(stdout);
  455.     }
  456. }
  457.  
  458. int
  459. semstat()
  460. {
  461.     int i;
  462.     int semval, sempid, semncnt, semzcnt;
  463.     union semun ignore;
  464.     ignore.val = 0;
  465.  
  466.     for (i = 0; SemNames[i] != (char *) NULL; i++) {
  467.     if ((semval = semctl(SemaphoreId, i, GETVAL, ignore)) < 0) {
  468.         perror(SemNames[i]);
  469.         return(-errno);
  470.     }
  471.     if ((sempid = semctl(SemaphoreId, i, GETPID, ignore)) < 0) {
  472.         perror(SemNames[i]);
  473.         return(-errno);
  474.     }
  475.     if ((semncnt = semctl(SemaphoreId, i, GETNCNT, ignore)) < 0) {
  476.         perror(SemNames[i]);
  477.         return(-errno);
  478.     }
  479.     if ((semzcnt = semctl(SemaphoreId, i, GETZCNT, ignore)) < 0) {
  480.         perror(SemNames[i]);
  481.         return(-errno);
  482.     }
  483.     printf("%s%*sval %3d, last pid %d, ncnt %d, zcnt %d\n",
  484.         SemNames[i],
  485.         30 - strlen(SemNames[i]), "",
  486.         semval, sempid, semncnt, semzcnt);
  487.     }
  488. }
  489.  
  490. int
  491. quit()
  492. {
  493.     return (-1);
  494. }
  495.  
  496. int
  497. help()
  498. {
  499.     printf("semstat\t\t\tshow status of system semaphores\n");
  500.     printf("semset n val\t\tset semaphore n to val\n");
  501.     printf("\n");
  502.     printf("bufdesc n\t\tprint buffer descriptor n\n");
  503.     printf("bufdescs\t\tprint all buffer descriptors\n");
  504.     printf("buffer n type level\tshow contents of buffer n, which is a page from a\n");
  505.     printf("\t\t\ttype (h,b,r) relation, with level (0,1,2) detail\n");
  506.     printf("linp n which\t\tprint line pointer which of buffer n\n");
  507.     printf("tuple n type which\tprint tuple which of buffer n, which is a page from\n");
  508.     printf("\t\t\ta type (h,b,r) relation\n");
  509.     printf("\n");
  510.     printf("setbase val\t\tuse val as the logical shmem base address\n");
  511.     printf("shmemstat\t\tprint shared memory layout and stats\n");
  512.     printf("whatis ptr\t\twhat shared memory object is ptr?\n");
  513.     printf("\n");
  514.     printf("help\t\t\tprint this command summary\n");
  515.     printf("quit\t\t\texit\n");
  516.  
  517.     return (0);
  518. }
  519.  
  520. int
  521. semset(n, val)
  522.     char *n;
  523.     char *val;
  524. {
  525.     int semno;
  526.     union semun semval;
  527.  
  528.     semno = atoi(n);
  529.     if (semno < 0 || semno > MAX_SPINS) {
  530.     fprintf(stderr, "sem number out of range: shd be between 0 and %d\n",
  531.         MAX_SPINS);
  532.     return (1);
  533.     }
  534.  
  535.     semval.val = atoi(val);
  536.  
  537.     if (semctl(SemaphoreId, semno, SETVAL, semval) < 0) {
  538.     perror("semset");
  539.     return (1);
  540.     }
  541.  
  542.     return (0);
  543. }
  544.  
  545. /* XXX yikes */
  546. void
  547. shmemsplit(region)
  548.     char *region;
  549. {
  550.     BindingTable = region;
  551.     region += (60 + 1024 + 2040);
  552.     region += 16;            /* XXX this 16 is mysterious to me */
  553.     BufferDescriptors = (BufferDesc *) region;
  554.     region += 4420;
  555.     BufferBlocks = region;
  556.     region += 524288;
  557. #ifndef HAS_TEST_AND_SET
  558.     NWaitIOBackend = (int *) region;
  559.     region += 4;
  560. #endif /* ndef HAS_TEST_AND_SET */
  561.     BufHashTable = region;
  562.     region += (68 + 1024);
  563.     LockTableCtl = region;
  564.     region += 60;
  565.     LockTableLockHash = region;
  566.     region += (72 + 1024);
  567.     LockTableXIDHash = region;
  568.     region += (72 + 1024);
  569.     LastKnownSMAddr = region;
  570. }
  571.  
  572. int
  573. setbase(addr)
  574.     char *addr;
  575. {
  576.     Base = (char *) strtol(addr, (char *) NULL, 0);
  577.     return (0);
  578. }
  579.  
  580. int
  581. whatis(addr)
  582.     char *addr;
  583. {
  584.     char *locn;
  585.     char *base;
  586.     int off;
  587.  
  588.     locn = (char *) strtol(addr, (char *) NULL, 0);
  589.     locn = (locn - Base) + SharedRegion;
  590.  
  591.     if (locn >= BindingTable && locn < (char *) BufferDescriptors) {
  592.     if (locn > BindingTable)
  593.         printf("pointer into ");
  594.     printf("binding table\n");
  595.     } else if (locn >= (char *) BufferDescriptors && locn < BufferBlocks) {
  596.     base = (char *) BufferDescriptors;
  597.     off = (locn - base) / sizeof(BufferDesc);
  598.     if ((locn - base) % sizeof(BufferDesc) != 0)
  599.         printf("pointer into ");
  600.     printf("buffer desc %d\n", off);
  601.     } else if (locn >= BufferBlocks
  602. #ifndef HAS_TEST_AND_SET
  603.         && locn < (char *) NWaitIOBackend) {
  604. #else
  605.         && locn < BufHashTable) {
  606. #endif
  607.     base = BufferBlocks;
  608.     off = (locn - base) / 8192;
  609.     if ((locn - base) % 8192 != 0)
  610.         printf("byte %d of ", (locn - base) % 8192);
  611.     printf("buffer %d\n", off);
  612. #ifndef HAS_TEST_AND_SET
  613.     } else if (locn >= (char *) NWaitIOBackend
  614.            && locn < BufHashTable) {
  615.     if (locn != (char *) NWaitIOBackend)
  616.         printf("pointer into ");
  617.     printf("number of backends waiting for i/o to complete\n");
  618. #endif
  619.     } else if (locn >= BufHashTable && locn < LockTableCtl) {
  620.     if (locn > BufHashTable)
  621.         printf("pointer into ");
  622.     printf("buffer hash table\n");
  623.     } else if (locn >= LockTableCtl && locn < LockTableLockHash) {
  624.     if (locn > LockTableCtl)
  625.         printf("pointer into ");
  626.     printf("lock table control\n");
  627.     } else if (locn >= LockTableLockHash && locn < LockTableXIDHash) {
  628.     if (locn > LockTableLockHash)
  629.         printf("pointer into ");
  630.     printf("lock table (lock hash)\n");
  631.     } else if (locn >= LockTableXIDHash && locn < LastKnownSMAddr) {
  632.     if (locn > LockTableXIDHash)
  633.         printf("pointer into ");
  634.     printf("lock table (xid hash)\n");
  635.     } else if (locn >= LastKnownSMAddr && locn < SharedRegionEnd) {
  636.     printf("unknown shared memory pointer\n");
  637.     } else
  638.     printf("not a shared memory pointer\n");
  639.  
  640.     return (0);
  641. }
  642.  
  643. #define    XLATE(p)    ((((char *) p) - SharedRegion) + Base)
  644.  
  645. int
  646. shmemstat()
  647. {
  648.     printf("shared region                0x%lx - 0x%lx\n",
  649.        XLATE(SharedRegion), XLATE(SharedRegionEnd));
  650.     printf("binding table                0x%lx\n", XLATE(BindingTable));
  651.     printf("buffer descriptors           0x%lx\n", XLATE(BufferDescriptors));
  652.     printf("buffer blocks                0x%lx\n", XLATE(BufferBlocks));
  653. #ifndef HAS_TEST_AND_SET
  654.     printf("# backends waiting on i/o    0x%lx\n", XLATE(NWaitIOBackend));
  655. #endif /* ndef HAS_TEST_AND_SET */
  656.     printf("buffer hash table            0x%lx\n", XLATE(BufHashTable));
  657.     printf("lock table control           0x%lx\n", XLATE(LockTableCtl));
  658.     printf("lock table (lock hash)       0x%lx\n", XLATE(LockTableLockHash));
  659.     printf("lock table (xid hash)        0x%lx\n", XLATE(LockTableXIDHash));
  660.     printf("last known shared mem addr   0x%lx\n", XLATE(LastKnownSMAddr));
  661.  
  662.     return (0);
  663. }
  664.  
  665. int
  666. showbufd(i)
  667.     int i;
  668. {
  669.     BufferDesc *d;
  670.  
  671.     d = &BufferDescriptors[i];
  672.     printf("[%02d]\tnext %d, prev %d, data 0x%lx, relid %d, dbid %d, blkno %d\n", 
  673.         i, d->freeNext, d->freePrev, XLATE(d->data), d->tag.relId.relId,
  674.         d->tag.relId.dbId, d->tag.blockNum);
  675.     printf("\tid %d, flags 0x%x, smgr %d, refcnt %d, db '%.16s', rel '%.16s'\n",
  676.         d->id, d->flags, d->bufsmgr, d->refcount,
  677.         &(d->sb_dbname[0]), &(d->sb_relname[0]));
  678. #ifdef HAS_TEST_AND_SET
  679.     printf("\tiolock 0xlx\n", d->io_in_progress_lock);
  680. #endif
  681. }
  682.  
  683. bufdescs()
  684. {
  685.     BufferDesc *d;
  686.     int i;
  687.  
  688.     for (i = 0; i < NBuffers; i++)
  689.     showbufd(i);
  690.  
  691.     return (0);
  692. }
  693.  
  694. int
  695. bufdesc(bno)
  696.     char *bno;
  697. {
  698.     int i;
  699.  
  700.     i = atoi(bno);
  701.  
  702.     if (i < 0 || i >= NBuffers) {
  703.     fprintf(stderr, "buffer number %d out of range (0 to %d)\n",
  704.         i, NBuffers);
  705.     return (1);
  706.     }
  707.  
  708.     showbufd(i);
  709.  
  710.     return (0);
  711. }
  712.  
  713. extern int        buffer();
  714. extern void        heappage();
  715. extern void        btreepage();
  716. extern void        rtreepage();
  717. extern void        showlinp();
  718. extern void        showheaptup();
  719. extern void        showindextup();
  720. extern int        PageGetNEntries();
  721. extern unsigned long    ItemPointerGetBlockNumber();
  722.  
  723. int
  724. buffer(pgno, type, level)
  725.     char *pgno;
  726.     char *type;
  727.     char *level;
  728. {
  729.     int p, l;
  730.     int off;
  731.  
  732.     p = atoi(pgno);
  733.     if (p < 0 || p >= NBuffers) {
  734.     fprintf(stderr, "buffer number %d out of range (0 - %d)\n",
  735.         p, NBuffers);
  736.     return (1);
  737.     }
  738.     off = p * 8192;
  739.  
  740.     l = atoi(level);
  741.     if (l < 0) {
  742.     fprintf(stderr, "level %d out of range -- must be non-negative\n", l);
  743.     return (1);
  744.     }
  745.  
  746.     switch (*type) {
  747.     case 'h':
  748.         heappage(BufferDescriptors[p].tag.blockNum,
  749.              &(BufferBlocks[off]), l);
  750.         break;
  751.     case 'b':
  752.         btreepage(BufferDescriptors[p].tag.blockNum,
  753.              &(BufferBlocks[off]), l);
  754.         break;
  755.     case 'r':
  756.         rtreepage(BufferDescriptors[p].tag.blockNum,
  757.              &(BufferBlocks[off]), l);
  758.         break;
  759.     default:
  760.         /* should never happen */
  761.         fprintf(stderr, "type '%s' should be h, r, or b\n", type);
  762.         return (1);
  763.     }
  764.  
  765.     return (0);
  766. }
  767.  
  768. void
  769. heappage(pgno, buf, level)
  770.     int pgno;
  771.     char *buf;
  772.     int level;
  773. {
  774.     PageHeaderData *phdr;
  775.     ItemIdData *lp;
  776.     int nlinps;
  777.     int i;
  778.     HeapTupleData *htup;
  779.  
  780.     phdr = (PageHeaderData *) buf;
  781.     nlinps = PageGetNEntries(phdr);
  782.     printf("lower: %d upper: %d special: %d opaque 0x%hx (%d items)\n",
  783.         phdr->pd_lower, phdr->pd_upper, phdr->pd_special,
  784.         phdr->pd_opaque, nlinps);
  785.     if (phdr->pd_lower < 8)
  786.     printf("    **** lower too low!\n");
  787.     if (phdr->pd_lower > 8192)
  788.     printf("    **** lower too high!\n");
  789.     if (phdr->pd_upper < 12)
  790.     printf("    **** upper too low!\n");
  791.     if (phdr->pd_upper > 8192)
  792.     printf("    **** upper too high!\n");
  793.     if (phdr->pd_special > 8192)
  794.     printf("    **** special too high!\n");
  795.  
  796.     /* level 0 is page headers only */
  797.     if (level == 0)
  798.     return;
  799.  
  800.     for (i = 0, lp = &(phdr->pd_linp[0]); i < nlinps; lp++, i++) {
  801.     showlinp(i, lp);
  802.     /* level > 1 means show everything */
  803.     if (level > 1) {
  804.         htup = (HeapTupleData *) &(buf[lp->lp_off]);
  805.         showheaptup(htup);
  806.     }
  807.     }
  808. }
  809.  
  810. void
  811. btreepage(pgno, buf, level)
  812.     char *buf;
  813.     int level;
  814. {
  815.     PageHeaderData *phdr;
  816.     ItemIdData *lp;
  817.     int nlinps;
  818.     int i;
  819.     BTItemData *bti;
  820.     BTPageOpaqueData *btpo;
  821.     BTMetaPageData *meta;
  822.  
  823.     /* if this is the btree metadata page, handle it specially */
  824.     if (pgno == 0) {
  825.     meta = (BTMetaPageData *) buf;
  826.     printf("metapage: magic 0x%06lx version %ld root %ld freelist %ld\n",
  827.         meta->btm_magic, meta->btm_version, meta->btm_root,
  828.         meta->btm_freelist);
  829.     if (meta->btm_magic != 0x053162)
  830.         printf("    **** magic number is bogus!\n");
  831.  
  832.     return;
  833.     }
  834.  
  835.     phdr = (PageHeaderData *) buf;
  836.     nlinps = PageGetNEntries(phdr);
  837.     printf("lower: %d upper: %d special: %d opaque 0x%hx (%d items)\n",
  838.         phdr->pd_lower, phdr->pd_upper, phdr->pd_special,
  839.         phdr->pd_opaque, nlinps);
  840.     btpo = (BTPageOpaqueData *) &(buf[phdr->pd_special]);
  841.     printf("\tprev %d next %d", btpo->btpo_prev, btpo->btpo_next);
  842.     if (btpo->btpo_flags & BTP_LEAF)
  843.     printf(" <leaf>");
  844.     if (btpo->btpo_flags & BTP_ROOT)
  845.     printf(" <root>");
  846.     if (!(btpo->btpo_flags & (BTP_LEAF|BTP_ROOT)))
  847.     printf(" <internal>");
  848.     if (btpo->btpo_flags & BTP_FREE)
  849.     printf(" <free>");
  850.     if (btpo->btpo_next != 0)
  851.     printf(" (item 001 is high key on page)");
  852.     else
  853.     printf(" (no high key)");
  854.     printf("\n");
  855.     if (phdr->pd_lower < 8)
  856.     printf("    **** lower too low!\n");
  857.     if (phdr->pd_lower > 8192)
  858.     printf("    **** lower too high!\n");
  859.     if (phdr->pd_upper < 12)
  860.     printf("    **** upper too low!\n");
  861.     if (phdr->pd_upper > 8192)
  862.     printf("    **** upper too high!\n");
  863.     if (phdr->pd_special > 8192)
  864.     printf("    **** special too high!\n");
  865.  
  866.     /* level 0 is page headers only */
  867.     if (level == 0)
  868.     return;
  869.  
  870.     for (i = 0, lp = &(phdr->pd_linp[0]); i < nlinps; lp++, i++) {
  871.     showlinp(i, lp);
  872.     /* level > 1 means show everything */
  873.     if (level > 1) {
  874.         bti = (BTItemData *) &(buf[lp->lp_off]);
  875.         printf("\t\toid %ld ", bti->bti_oid);
  876.         showindextup(&bti->bti_itup);
  877.     }
  878.     }
  879. }
  880.  
  881. void
  882. rtreepage(pgno, buf, level)
  883.     int pgno;
  884.     char *buf;
  885.     int level;
  886. {
  887.     PageHeaderData *phdr;
  888.     ItemIdData *lp;
  889.     int nlinps;
  890.     int i;
  891.     RTreePageOpaqueData *rtpo;
  892.     IndexTupleData *itup;
  893.  
  894.     phdr = (PageHeaderData *) buf;
  895.     rtpo = (RTreePageOpaqueData *) &(buf[phdr->pd_special]);
  896.     nlinps = PageGetNEntries(phdr);
  897.     printf("lower: %d upper: %d special: %d opaque 0x%hx %s (%d items)\n",
  898.         phdr->pd_lower, phdr->pd_upper, phdr->pd_special,
  899.         phdr->pd_opaque,
  900.         ((rtpo->rtpo_flags & RTF_LEAF) ? "<leaf>":"internal"), nlinps);
  901.     if (phdr->pd_lower < 8)
  902.     printf("    **** lower too low!\n");
  903.     if (phdr->pd_lower > 8192)
  904.     printf("    **** lower too high!\n");
  905.     if (phdr->pd_upper < 12)
  906.     printf("    **** upper too low!\n");
  907.     if (phdr->pd_upper > 8192)
  908.     printf("    **** upper too high!\n");
  909.     if (phdr->pd_special > 8192)
  910.     printf("    **** special too high!\n");
  911.  
  912.     /* level 0 is page headers only */
  913.     if (level == 0)
  914.     return;
  915.  
  916.     for (i = 0, lp = &(phdr->pd_linp[0]); i < nlinps; lp++, i++) {
  917.     showlinp(i, lp);
  918.     /* level > 1 means show everything */
  919.     if (level > 1) {
  920.         itup = (IndexTupleData *) &(buf[lp->lp_off]);
  921.         showindextup(itup);
  922.     }
  923.     }
  924. }
  925.  
  926. void
  927. showlinp(itemno, lp)
  928.     int itemno;
  929.     ItemIdData *lp;
  930. {
  931.     int off;
  932.  
  933.     printf("  {%03d} off %d length %d flags [",
  934.        itemno + 1, lp->lp_off, lp->lp_len);
  935.     if (lp->lp_flags & LP_USED)
  936.     printf(" LP_USED");
  937.     if (lp->lp_flags & LP_IVALID)
  938.     printf(" LP_IVALID");
  939.     if (lp->lp_flags & LP_DOCNT)
  940.     printf(" LP_DOCNT");
  941.     if (lp->lp_flags & LP_CTUP)
  942.     printf(" LP_CTUP");
  943.     if (lp->lp_flags & LP_LOCK)
  944.     printf(" LP_LOCK");
  945.     if (lp->lp_flags & LP_ISINDEX)
  946.     printf(" LP_ISINDEX");
  947.     printf(" ]\n");
  948.     if ((off = lp->lp_off) > 8192)
  949.     printf("    **** off too high!\n");
  950.     if (off & 0x3)
  951.     printf("    **** off is bogus -- unaligned tuple pointer!");
  952.     if (lp->lp_len > 8192)
  953.     printf("    **** len too high!\n");
  954.     if (!(lp->lp_flags & LP_USED))
  955.     printf("    **** item not used!\n");
  956. }
  957.  
  958. void
  959. showheaptup(htup)
  960.     HeapTupleData *htup;
  961. {
  962.     printf("\tlen %d ctid <%d,0,%d> chain <%d,0,%d> oid %ld cmin/max %d/%d\n",
  963.        htup->t_len, ItemPointerGetBlockNumber(htup->t_ctid.block),
  964.        htup->t_ctid.offset, ItemPointerGetBlockNumber(htup->t_chain.block),
  965.        htup->t_chain.offset, htup->t_oid, htup->t_cmin, htup->t_cmax);
  966.     printf("\txmin/max %ld/%ld tmin/max %ld/%ld natts %d\n",
  967.        htup->t_xmin, htup->t_xmax, htup->t_tmin, htup->t_tmax,
  968.        htup->t_natts);
  969.     printf("\tvtype '\\%03o' infomask 0x%x locktype '%c'\n",
  970.        htup->t_vtype, htup->t_infomask, htup->t_locktype);
  971. }
  972.  
  973. void
  974. showindextup(itup)
  975.     IndexTupleData *itup;
  976. {
  977.     printf("heap tid <%d,0,%d> info [",
  978.        ItemPointerGetBlockNumber(itup->t_tid.block), itup->t_tid.offset);
  979.     if (itup->t_info & ITUP_HASNULLS)
  980.     printf(" HASNULLS");
  981.     if (itup->t_info & ITUP_HASVARLENA)
  982.     printf(" HASVARLENA");
  983.     if (itup->t_info & ITUP_HASRULES)
  984.     printf(" HASRULES");
  985.     printf(" ] length %d\n", itup->t_info & ITUP_LENMASK);
  986. }
  987.  
  988. int
  989. PageGetNEntries(phdr)
  990.     PageHeaderData *phdr;
  991. {
  992.     int n;
  993.  
  994.     n = (phdr->pd_lower - (2 * sizeof(unsigned long))) / sizeof(ItemIdData);
  995.  
  996.     return (n);
  997. }
  998.  
  999. unsigned long
  1000. ItemPointerGetBlockNumber(iptr)
  1001.     ItemPointerData *iptr;
  1002. {
  1003.     unsigned long b;
  1004.  
  1005.     b = (unsigned long) ((iptr->block[0] << 16) + iptr->block[1]);
  1006.  
  1007.     return (b);
  1008. }
  1009.  
  1010. int
  1011. linp(pgno, which)
  1012.     char *pgno;
  1013.     char *which;
  1014. {
  1015.     int p, n;
  1016.     int off;
  1017.     PageHeaderData *phdr;
  1018.  
  1019.     p = atoi(pgno);
  1020.     if (p < 0 || p >= NBuffers) {
  1021.     fprintf(stderr, "buffer number %d out of range (0 - %d)\n",
  1022.         p, NBuffers);
  1023.     return (1);
  1024.     }
  1025.  
  1026.     n = atoi(which);
  1027.     if (n < 0) {
  1028.     fprintf(stderr, "linp %d out of range -- must be non-negative\n", n);
  1029.     return (1);
  1030.     }
  1031.  
  1032.     off = p * 8192;
  1033.     phdr = (PageHeaderData *) &(BufferBlocks[off]);
  1034.  
  1035.     showlinp(n, &(phdr->pd_linp[n]));
  1036.  
  1037.     return (0);
  1038. }
  1039.  
  1040. int
  1041. tuple(pgno, type, which)
  1042.     char *pgno;
  1043.     char *type;
  1044.     char *which;
  1045. {
  1046.     int p, n;
  1047.     int off;
  1048.     PageHeaderData *phdr;
  1049.     ItemIdData *lp;
  1050.     BTItemData *bti;
  1051.     char *buf;
  1052.  
  1053.     p = atoi(pgno);
  1054.     if (p < 0 || p >= NBuffers) {
  1055.     fprintf(stderr, "buffer number %d out of range (0 - %d)\n",
  1056.         p, NBuffers);
  1057.     return (1);
  1058.     }
  1059.  
  1060.     n = atoi(which);
  1061.     if (n < 0) {
  1062.     fprintf(stderr, "linp %d out of range -- must be non-negative\n", n);
  1063.     return (1);
  1064.     }
  1065.  
  1066.     off = p * 8192;
  1067.     phdr = (PageHeaderData *) &(BufferBlocks[off]);
  1068.     buf = (char *) phdr;
  1069.     lp = &(phdr->pd_linp[n]);
  1070.  
  1071.     switch (*type) {
  1072.     case 'r':
  1073.         showindextup((IndexTupleData *) &(buf[lp->lp_off]));
  1074.         break;
  1075.  
  1076.     case 'b':
  1077.         bti = (BTItemData *) &(buf[lp->lp_off]);
  1078.         showindextup(&bti->bti_itup);
  1079.         break;
  1080.  
  1081.     case 'h':
  1082.         showheaptup((HeapTupleData *) &(buf[lp->lp_off]));
  1083.         break;
  1084.  
  1085.     default:
  1086.         fprintf(stderr, "type %s unknown -- try h, r, or b\n", type);
  1087.         fflush(stderr);
  1088.         return (1);
  1089.     }
  1090.  
  1091.     return (0);
  1092. }
  1093.